home *** CD-ROM | disk | FTP | other *** search
/ Aminet 2 / Aminet AMIGA CDROM (1994)(Walnut Creek)[Feb 1994][W.O. 44790-1].iso / Aminet / comm / misc / xprz31.lha / XprZmodem / Utils.c < prev    next >
C/C++ Source or Header  |  1993-08-13  |  38KB  |  1,311 lines

  1.  /**********************************************************************
  2.   * Utils.c: Miscellaneous support routines for xprzmodem.library;
  3.   * Version 2.10, 12 February 1991, by Rick Huebner.
  4.   * Released to the Public Domain; do as you like with this code.
  5.   *
  6.   * Version 2.50, 15 November 1991, by William M. Perkins.  Added code
  7.   * to update_rate() function in utils.c to avoid the Guru # 80000005
  8.   * you would have gotten if you had decided to adjust the system clock
  9.   * back during an upload or download.
  10.   *
  11.   * Mysprintf() function to replace sprintf() and proto code to use
  12.   * libinit.o and linent.o library code was supplied by Jim Cooper of SAS.
  13.   *
  14.   * Version 2.61, 3 July 1993 Mysprintf changed to xprsprintf(), written
  15.   * in Assembler, because under SAS/C the old code running not correctly.
  16.   *
  17.   * Version 2.62, 27 July 1993 build in variable Blocksize.
  18.   *
  19.   * Version 2.63, 30 July 1993 build in locale, by Rainer Hess
  20.   *
  21.   * Version 2.64,  3 Aug 1993 global vaiable Blocksize, now in
  22.   *                 struct Vars, by Rainer Hess
  23.   *
  24.   *                4 Aug 1993 changes in update_rate() function because
  25.   * it always GURU 8000 0005 on little files (testet with 2 byte-file)
  26.   * when you send. If on receiver the file exists when receiver ask for
  27.   * overwrite, the machine crash if you click overwrite on receiver.
  28.   * Testet on Term 3.4 -> Ncomm 2.0, by Rainer Hess
  29.   *
  30.   **********************************************************************/
  31.  
  32. #include "xprzmodem_all.h"
  33.  
  34. #define CATCOMP_NUMBERS
  35. #include "xprzmodem_catalog.h"
  36.  
  37. /*
  38.  * Transfer options to use if XProtocolSetup not called
  39.  */
  40.  
  41. struct SetupVars Default_Config =
  42. {
  43.   NULL,                /* = *matchptr  */
  44.   NULL,                /* = *bufpos    */
  45.   0,                /* = buflen     */
  46.   "C",                /* option_t[2]  */
  47.   "N",                /* option_o[2]  */
  48.   "16",                /* option_b[8]  */
  49.   "0",                /* option_f[8]  */
  50.   "10",                /* option_e[8]  */
  51.   "N",                /* option_s[4]  */
  52.   "N",                /* option_r[4]  */
  53.   "Y",                /* option_a[4]  */
  54.   "N",                /* option_d[4]  */
  55.   "Y",                /* option_k[4]  */
  56.   "",                /* option_p[256] */
  57.   "1024"            /* option_m[8]  */
  58. };
  59.  
  60. #ifdef DEBUGLOG
  61. UBYTE DebugName[] = "T:XDebug.Log";
  62. void *DebugLog = NULL;
  63. #endif
  64.  
  65. struct DosLibrary *DOSBase;
  66. struct ExecBase *SysBase;
  67.  
  68. #ifdef UP_TO_2X
  69. struct Library *UtilityBase;
  70. #endif
  71.  
  72. #define LIBRARY_ANY 0L
  73.  
  74. #define LocaleBase li.li_LocaleBase
  75. #define catalog    li.li_Catalog
  76.  
  77. struct LocaleInfo li;
  78.  
  79. struct TagItem LocalTags[3] =
  80. {
  81.   OC_BuiltInLanguage, (ULONG) "english",
  82.   OC_Version, 1,        /* Catalog-Nummer */
  83.   TAG_DONE
  84. };
  85.  
  86. /**********************************************************
  87.  *      int __UserLibInit(struct Library *libbase)
  88.  **********************************************************/
  89. int __saveds __asm
  90. __UserLibInit (register __a6 struct MyLibrary *libbase)
  91. {
  92.   SysBase = *(struct ExecBase **) 4L;
  93.   if (!(DOSBase = (struct DosLibrary *) OpenLibrary ("dos.library", LIBRARY_ANY)))
  94.     return (RETURN_FAIL);
  95.  
  96. #ifdef UP_TO_2X
  97.   if (!(UtilityBase = OpenLibrary ("utility.library", 37L)))
  98.     return (RETURN_FAIL);
  99. #endif
  100.  
  101.   if (LocaleBase = OpenLibrary ("locale.library", 38L))
  102.     catalog = OpenCatalogA (NULL, "xprzmodem.catalog", &LocalTags[0]);
  103.  
  104.   return (RETURN_OK);
  105. }                /* End of __UserLibInit() */
  106.  
  107. /**********************************************************
  108.  *      void __UserLibCleanup(struct Library *libbase)
  109.  **********************************************************/
  110. void __saveds __asm
  111. __UserLibCleanup (register __a6 struct MyLibrary *libbase)
  112. {
  113.   if (DOSBase)
  114.     CloseLibrary ((struct Library *) DOSBase);
  115.  
  116. #ifdef UP_TO_2X
  117.   if (UtilityBase)
  118.     CloseLibrary (UtilityBase);
  119. #endif
  120.  
  121.   if (LocaleBase)
  122.     {
  123.       if (catalog)
  124.     CloseCatalog (catalog);
  125.       CloseLibrary (LocaleBase);
  126.     }
  127. }                /* End of __UserLibCleanup() */
  128.  
  129. /**********************************************************
  130.  *      long XProtocolSetup(struct XPR_IO *xio)
  131.  *
  132.  * Called by comm program to set transfer options
  133.  **********************************************************/
  134. long __saveds __asm
  135. XProtocolSetup (register __a0 struct XPR_IO *xio)
  136. {
  137.   struct SetupVars *sv, tempsv;
  138.   struct xpr_option *option_ptrs[13];
  139.   struct xpr_option *optr, xo_hdr, xo_t, xo_o, xo_b, xo_f, xo_e, xo_s,
  140.     xo_r, xo_a, xo_d, xo_k, xo_p, xo_m;
  141.   UBYTE buf[256], *p;
  142.   long i, len;
  143.  
  144.   /* Allocate memory for transfer options string */
  145.   if (!(sv = (void *) xio->xpr_data))
  146.     {
  147.       xio->xpr_data = AllocMem ((ULONG) sizeof (struct SetupVars), MEMF_CLEAR);
  148.       if (!(sv = (void *) xio->xpr_data))
  149.     {
  150.       ioerr (xio, "Not enough memory!");
  151.       return XPRS_FAILURE;
  152.     }
  153.       /* Start out with default options; merge user changes into defaults */
  154.       *sv = Default_Config;
  155.     }
  156.  
  157.   /* If options string passed by comm prog, use it; else prompt user */
  158.   if (xio->xpr_filename)
  159.     strcpy (buf, xio->xpr_filename);
  160.   else
  161.     {
  162.       /* If xpr_options() implemented by comm program, use it */
  163.       if (xio->xpr_extension >= 1 && xio->xpr_options)
  164.     {
  165.       /*
  166.          * Let user edit temp copy of options so we can ignore invalid
  167.          * entries.  Have to init all this crud the hard way 'cause it's
  168.          * got to be on the stack in order to maintain reentrancy
  169.        */
  170.       tempsv = *sv;
  171.       xo_hdr.xpro_description = GetLocalString( &li, MSG_ZMODEM_OPTIONS );
  172.       xo_hdr.xpro_type = XPRO_HEADER;
  173.       xo_hdr.xpro_value = NULL;
  174.       xo_hdr.xpro_length = 0;
  175.       option_ptrs[0] = &xo_hdr;
  176.       xo_t.xpro_description = GetLocalString( &li, MSG_TEXT_MODE );
  177.       xo_t.xpro_type = XPRO_STRING;
  178.       xo_t.xpro_value = tempsv.option_t;
  179.       xo_t.xpro_length = sizeof (tempsv.option_t);
  180.       option_ptrs[1] = &xo_t;
  181.       xo_o.xpro_description = GetLocalString( &li, MSG_OVERWRITE_MODE );
  182.       xo_o.xpro_type = XPRO_STRING;
  183.       xo_o.xpro_value = tempsv.option_o;
  184.       xo_o.xpro_length = sizeof (tempsv.option_o);
  185.       option_ptrs[2] = &xo_o;
  186.       xo_b.xpro_description = GetLocalString( &li, MSG_IO_BUFFER_SIZE );
  187.       xo_b.xpro_type = XPRO_LONG;
  188.       xo_b.xpro_value = tempsv.option_b;
  189.       xo_b.xpro_length = sizeof (tempsv.option_b);
  190.       option_ptrs[3] = &xo_b;
  191.       xo_f.xpro_description = GetLocalString( &li, MSG_FRAME_SIZE );
  192.       xo_f.xpro_type = XPRO_LONG;
  193.       xo_f.xpro_value = tempsv.option_f;
  194.       xo_f.xpro_length = sizeof (tempsv.option_f);
  195.       option_ptrs[4] = &xo_f;
  196.       xo_e.xpro_description = GetLocalString( &li, MSG_ERROR_LIMIT );
  197.       xo_e.xpro_type = XPRO_LONG;
  198.       xo_e.xpro_value = tempsv.option_e;
  199.       xo_e.xpro_length = sizeof (tempsv.option_e);
  200.       option_ptrs[5] = &xo_e;
  201.       xo_a.xpro_description = GetLocalString( &li, MSG_AUTO_ACTIVATE_RECEIVER );
  202.       xo_a.xpro_type = XPRO_BOOLEAN;
  203.       xo_a.xpro_value = tempsv.option_a;
  204.       xo_a.xpro_length = sizeof (tempsv.option_a);
  205.       option_ptrs[6] = &xo_a;
  206.       xo_d.xpro_description = GetLocalString( &li, MSG_DELETE_AFTER_SENDING );
  207.       xo_d.xpro_type = XPRO_BOOLEAN;
  208.       xo_d.xpro_value = tempsv.option_d;
  209.       xo_d.xpro_length = sizeof (tempsv.option_d);
  210.       option_ptrs[7] = &xo_d;
  211.       xo_k.xpro_description = GetLocalString( &li, MSG_KEEP_PARTIAL_FILES );
  212.       xo_k.xpro_type = XPRO_BOOLEAN;
  213.       xo_k.xpro_value = tempsv.option_k;
  214.       xo_k.xpro_length = sizeof (tempsv.option_k);
  215.       option_ptrs[8] = &xo_k;
  216.       xo_s.xpro_description = GetLocalString( &li, MSG_SEND_FULL_PATH );
  217.       xo_s.xpro_type = XPRO_BOOLEAN;
  218.       xo_s.xpro_value = tempsv.option_s;
  219.       xo_s.xpro_length = sizeof (tempsv.option_s);
  220.       option_ptrs[9] = &xo_s;
  221.       xo_r.xpro_description = GetLocalString( &li, MSG_USE_RECEIVED_PATH );
  222.       xo_r.xpro_type = XPRO_BOOLEAN;
  223.       xo_r.xpro_value = tempsv.option_r;
  224.       xo_r.xpro_length = sizeof (tempsv.option_r);
  225.       option_ptrs[10] = &xo_r;
  226.       xo_p.xpro_description = GetLocalString( &li, MSG_DEFAULT_RECEIVE_PATH );
  227.       xo_p.xpro_type = XPRO_STRING;
  228.       xo_p.xpro_value = tempsv.option_p;
  229.       xo_p.xpro_length = sizeof (tempsv.option_p);
  230.       option_ptrs[11] = &xo_p;
  231.       xo_m.xpro_description = GetLocalString( &li, MSG_MAXIMUM_BLOCK_SIZE );
  232.       xo_m.xpro_type = XPRO_LONG;
  233.       xo_m.xpro_value = tempsv.option_m;
  234.       xo_m.xpro_length = sizeof (tempsv.option_m);
  235.       option_ptrs[12] = &xo_m;
  236.  
  237.       /* Convert Y/N used elsewhere into "yes"/"no" required by spec */
  238.       for (i = 6; i <= 10; ++i)
  239.         {
  240.           optr = option_ptrs[i];
  241.           strcpy (optr->xpro_value, (*optr->xpro_value == 'Y') ? "yes" : "no");
  242.         }
  243.  
  244.       (*xio->xpr_options) (13L, option_ptrs);
  245.  
  246.       /* Convert "yes"/"no" or "on"/"off" into Y/N */
  247.       for (i = 6; i <= 10; ++i)
  248.         {
  249.           optr = option_ptrs[i];
  250.           strcpy (optr->xpro_value, (!stricmp (optr->xpro_value, "yes")
  251.              || !stricmp (optr->xpro_value, "on")) ? "Y" : "N");
  252.         }
  253.       /* Convert xpr_options() results into parseable options string */
  254.       xprsprintf (buf, "T%s,O%s,B%s,F%s,E%s,A%s,D%s,K%s,S%s,R%s,P%s,M%s",
  255.       tempsv.option_t, tempsv.option_o, tempsv.option_b, tempsv.option_f,
  256.       tempsv.option_e, tempsv.option_a, tempsv.option_d, tempsv.option_k,
  257.               tempsv.option_s, tempsv.option_r, tempsv.option_p, tempsv.option_m);
  258.       /* If xpr_options() not provided, try xpr_gets() instead */
  259.     }
  260.       else
  261.     {
  262.       /* Start buffer with current settings so user can see/edit them. */
  263.       xprsprintf (buf, "T%s,O%s,B%s,F%s,E%s,A%s,D%s,K%s,S%s,R%s,P%s,M%s",
  264.               sv->option_t, sv->option_o, sv->option_b, sv->option_f,
  265.               sv->option_e, sv->option_a, sv->option_d, sv->option_k,
  266.             sv->option_s, sv->option_r, sv->option_p, sv->option_m);
  267.       if (xio->xpr_gets)
  268.         (*xio->xpr_gets) ( GetLocalString( &li, MSG_ZMODEM_OPTIONS ), buf);
  269.     }
  270.     }
  271.   /* Upshift options string for easier parsing */
  272.   strupr (buf);
  273.  
  274.   /*
  275.      * Merge new T(ext) option into current settings if given
  276.      *  "TY" = Force Text mode on,
  277.      *  "TN" = Force Text mode off,
  278.      *  "T?" = Use other end's text mode suggestion (default to binary)
  279.      *  "TC" = Ask Comm program for file type
  280.    */
  281.   if (p = find_option (buf, 'T'))
  282.     {
  283.       if (*p == 'Y' || *p == 'N' || *p == '?' || *p == 'C')
  284.     *sv->option_t = *p;
  285.       else
  286.     ioerr (xio, "Invalid T flag ignored; should be Y, N, ?, or C");
  287.     }
  288.  
  289.   /*
  290.      * Merge new O(verwrite) option into current settings if given
  291.      *  "OY" = Yes, delete old file and replace with new one,
  292.      *  "ON" = No, prevent overwrite by appending ".dup" to avoid name collision,
  293.      *  "OR" = Resume transfer at end of existing file,
  294.      *  "OS" = Skip file if it already exists; go on to next
  295.    */
  296.   if (p = find_option (buf, 'O'))
  297.     {
  298.       if (*p == 'R' && !xio->xpr_finfo)
  299.     ioerr (xio, GetLocalString( &li, MSG_NO_XPR_FINFO ));
  300.       else if (*p == 'Y' || *p == 'N' || *p == 'R' || *p == 'S')
  301.     *sv->option_o = *p;
  302.       else
  303.     ioerr (xio, GetLocalString( &li, MSG_INVALID_O_FLAG ));
  304.     }
  305.  
  306.   /*
  307.      * Merge new B(uffer) setting into current settings if given
  308.      * Size of file I/O buffer in kilobytes
  309.    */
  310.   if (p = find_option (buf, 'B'))
  311.     {
  312.       len = atol (p);
  313.       if (len < 1)
  314.     len = 1;
  315.       xprsprintf (sv->option_b, "%ld", len);
  316.     }
  317.  
  318.   /*
  319.      * Merge new F(ramelength) setting into other settings if given
  320.      * Number of bytes we're willing to send or receive between ACKs.
  321.      * 0 = unlimited; nonstop streaming data
  322.    */
  323.   if (p = find_option (buf, 'F'))
  324.     {
  325.       len = atol (p);
  326.       if (len < 0)
  327.     len = 0;
  328.       if (len > 0 && len < MINBLOCK)
  329.     len = MINBLOCK;
  330.       xprsprintf (sv->option_f, "%ld", len);
  331.     }
  332.  
  333.   /*
  334.      * Merge new E(rror limit) setting into other settings if given
  335.      * Number of sequential errors which will cause an abort
  336.    */
  337.   if (p = find_option (buf, 'E'))
  338.     {
  339.       len = atol (p);
  340.       if (len < 1)
  341.     len = 1;
  342.       if (len > 32767)
  343.     len = 32767;
  344.       xprsprintf (sv->option_e, "%ld", len);
  345.     }
  346.  
  347.   /*
  348.      * Merge new A(uto-activate) setting into other settings if given
  349.      *  "AY" = Automatically call XProtocolReceive() if ZRQINIT string received
  350.      *  "AN" = Don't look for ZRQINIT; user will explicitly activate receive
  351.    */
  352.   if (p = find_option (buf, 'A'))
  353.     {
  354.       if (*p == 'Y' || *p == 'N')
  355.     *sv->option_a = *p;
  356.       else
  357.     ioerr (xio, GetLocalString( &li, MSG_INVALID_A_FLAG ));
  358.     }
  359.  
  360.   /*
  361.      * Merge new D(elete after sending) setting into other options
  362.      *  "DY" = Delete files after successfully sending them
  363.      *  "DN" = Don't delete files after sending
  364.    */
  365.   if (p = find_option (buf, 'D'))
  366.     {
  367.       if (*p == 'Y' && (xio->xpr_extension < 2 || !xio->xpr_unlink))
  368.     ioerr (xio, GetLocalString( &li, MSG_NO_DY_XPR_UNLINK ));
  369.       else if (*p == 'Y' || *p == 'N')
  370.     *sv->option_d = *p;
  371.       else
  372.     ioerr (xio, GetLocalString( &li, MSG_INVALID_D_FLAG ));
  373.     }
  374.  
  375.   /*
  376.      * Merge new K(eep partial files) setting into other options
  377.      *  "KY" = Keep partially-received file fragments to allow later resumption
  378.      *  "KN" = Delete partially-received file fragments
  379.    */
  380.   if (p = find_option (buf, 'K'))
  381.     {
  382.       if (*p == 'N' && (xio->xpr_extension < 2 || !xio->xpr_unlink))
  383.     ioerr (xio, GetLocalString( &li, MSG_NO_KN_XPR_UNLINK ));
  384.       else if (*p == 'Y' || *p == 'N')
  385.     *sv->option_k = *p;
  386.       else
  387.     ioerr (xio, GetLocalString( &li, MSG_INVALID_K_FLAG ));
  388.     }
  389.  
  390.   /*
  391.      * Merge new S(end full path) setting into other options
  392.      *  "SY" = Send full filename including directory path to receiver
  393.      *  "SN" = Send only simple filename portion, not including directory path
  394.    */
  395.   if (p = find_option (buf, 'S'))
  396.     {
  397.       if (*p == 'Y' || *p == 'N')
  398.     *sv->option_s = *p;
  399.       else
  400.     ioerr (xio, GetLocalString( &li, MSG_INVALID_S_FLAG ));
  401.     }
  402.  
  403.   /*
  404.      * Merge new R(eceive path) setting into other options
  405.      *  "RY" = Use full filename exactly as received; don't use P option path
  406.      *  "RN" = Ignore received directory path if any; use path from P option
  407.    */
  408.   if (p = find_option (buf, 'R'))
  409.     {
  410.       if (*p == 'Y' || *p == 'N')
  411.     *sv->option_r = *p;
  412.       else
  413.     ioerr (xio, GetLocalString( &li, MSG_INVALID_R_FLAG ));
  414.     }
  415.  
  416.   /*
  417.      * Merge new P(ath) setting into other options
  418.      *  "Pdir" = Receive files into directory "dir" if RN selected
  419.      *  "dir" can by any valid existing directory, with or without trailing "/"
  420.    */
  421.   if (p = find_option (buf, 'P'))
  422.     {
  423.       strcpy (sv->option_p, p);
  424.       p = sv->option_p + strcspn (sv->option_p, " ,\t\r\n");
  425.       *p = '\0';
  426.     }
  427.  
  428.   /*
  429.      * Maximum packet size. Must be <=8192
  430.    */
  431.  
  432.   if (p = find_option (buf, 'M'))
  433.     {
  434.       len = atol (p);
  435.       if (len < MINBLOCK)
  436.     len = MINBLOCK;
  437.       if (len > MAXGOODNEEDED)
  438.     len = KSIZE;
  439.  
  440.       xprsprintf (sv->option_m, "%ld", len);
  441.     }
  442.  
  443.   return (*sv->option_a == 'Y') ? XPRS_SUCCESS | XPRS_NORECREQ | XPRS_HOSTMON
  444.     : XPRS_SUCCESS | XPRS_NORECREQ;
  445. }                /* End of long XProtocolSetup() */
  446.  
  447. /**********************************************************
  448.  *      long XProtocolCleanup(struct XPR_IO *xio)
  449.  *
  450.  * Called by comm program to give us a chance to clean
  451.  * up before program ends
  452.  **********************************************************/
  453. long __saveds __asm
  454. XProtocolCleanup (register __a0 struct XPR_IO *xio)
  455. {
  456.   /* Release option memory, if any */
  457.   if (xio->xpr_data)
  458.     {
  459.       FreeMem (xio->xpr_data, (long) sizeof (struct SetupVars));
  460.       xio->xpr_data = NULL;
  461.     }
  462.  
  463.   return XPRS_SUCCESS;
  464. }                /* End of long XProtocolCleanup() */
  465.  
  466. /**********************************************************
  467.  *      long XProtocolHostMon(struct XPR_IO *xio,
  468.  *         char *serbuff, long actual, long maxsize)
  469.  *
  470.  * Called by comm program upon our request (XPRS_HOSTMON)
  471.  * to let us monitor the incoming data stream for our
  472.  * receiver auto-activation string (ZRQINIT packet).
  473.  * We only ask for this to be called if option AY is set.
  474.  **********************************************************/
  475. long __saveds __asm
  476. XProtocolHostMon (
  477.            register __a0 struct XPR_IO *xio,
  478.            register __a1 char *serbuff,
  479.            register __d0 long actual,
  480.            register __d1 long maxsize)
  481. {
  482.   static UBYTE startrcv[] =
  483.   {
  484.     ZPAD, ZDLE, ZHEX, '0', '0'
  485.   };
  486.   struct SetupVars *sv;
  487.  
  488.   if (!(sv = (void *) xio->xpr_data))
  489.     return actual;        /* XProtocolSetup() never called?! */
  490.  
  491.   if (!sv->matchptr)
  492.     sv->matchptr = startrcv;
  493.  
  494.   /*
  495.      * Scan through serbuff to see if we can match all bytes in the start
  496.      * string in sequence.
  497.    */
  498.   for (sv->bufpos = serbuff; sv->bufpos < serbuff + actual; ++sv->bufpos)
  499.     {
  500.       if (*sv->bufpos == *sv->matchptr)
  501.     {            /* if data matches current position in match */
  502.       ++sv->matchptr;    /* string, increment match position */
  503.       if (!*sv->matchptr)
  504.         {            /* if at end of match string, it all matched */
  505.           sv->buflen = actual - (sv->bufpos - serbuff);
  506.           XProtocolReceive (xio);
  507.           sv->matchptr = startrcv;
  508.           actual = 0;
  509.           break;
  510.         }
  511.     }
  512.       else if (sv->matchptr > startrcv)
  513.     {            /* mismatch?  Reset to start of match string */
  514.       sv->matchptr = startrcv;
  515.       if (*sv->bufpos == *sv->matchptr)
  516.         ++sv->matchptr;
  517.     }
  518.     }
  519.  
  520.   sv->bufpos = NULL;
  521.   return actual;
  522. }
  523.  
  524. /**********************************************************
  525.  *      long XProtocolUserMon(struct XPR_IO *xio,
  526.  *         char *serbuff, long actual, long maxsize)
  527.  *
  528.  * Called by comm program to let us monitor user's inputs;
  529.  * we never ask for this to be called, but it's better to
  530.  * recover gracefully than guru the machine.
  531.  **********************************************************/
  532. long __saveds __asm
  533. XProtocolUserMon (
  534.            register __a0 struct XPR_IO *xio,
  535.            register __a1 char *serbuff,
  536.            register __d0 long actual,
  537.            register __d1 long maxsize)
  538. {
  539.   return actual;
  540. }
  541.  
  542. /**********************************************************
  543.  *      struct Vars *setup(struct XPR_IO *io)
  544.  *
  545.  * Perform setup and initializations common to both Send
  546.  * and Receive routines
  547.  **********************************************************/
  548. struct Vars *
  549. setup (struct XPR_IO *io)
  550. {
  551.   static long bauds[] =
  552.   {
  553.     110, 300, 1200, 2400, 4800, 9600, 19200, 31250,
  554.     38400, 57600, 76800, 115200};
  555.   struct SetupVars *sv;
  556.   struct Vars *v;
  557.   long origbuf, newstatus;
  558.  
  559. #ifdef DEBUGLOG
  560.   long i, *lng;
  561. #endif
  562.  
  563.   /* Make sure comm program supports the required call-back functions */
  564.   if (!io->xpr_update)
  565.     return NULL;
  566.  
  567.   if (!io->xpr_fopen || !io->xpr_fclose || !io->xpr_fread
  568.       || !io->xpr_fwrite || !io->xpr_fseek || !io->xpr_sread
  569.       || !io->xpr_swrite)
  570.     {
  571.       ioerr (io, GetLocalString( &li, MSG_COMM_PROG_MISSING ));
  572.       return NULL;
  573.     }
  574.  
  575.   /* Hook in default transfer options if XProtocolSetup wasn't called */
  576.   if (!(sv = (void *) io->xpr_data))
  577.     {
  578.       io->xpr_data = AllocMem ((ULONG) sizeof (struct SetupVars), MEMF_CLEAR);
  579.       if (!(sv = (void *) io->xpr_data))
  580.     {
  581.       ioerr (io, GetLocalString( &li, MSG_NOT_ENOUGH_MEMORY ));
  582.       return NULL;
  583.     }
  584.       *sv = Default_Config;
  585.     }
  586.  
  587.   /* Allocate memory for our unshared variables, to provide reentrancy */
  588.   if (!(v = AllocMem ((ULONG) sizeof (struct Vars), MEMF_CLEAR)))
  589.     {
  590.     nomem:
  591.       ioerr (io, GetLocalString( &li, MSG_NOT_ENOUGH_MEMORY ));
  592.       return NULL;
  593.     }
  594.   v->Modemchar = v->Modembuf;
  595.  
  596.   /*
  597.      * Allocate memory for our file I/O buffer; if we can't get as much as
  598.      * requested, keep asking for less until we hit minimum before giving up
  599.    */
  600.   v->Filebufmax = origbuf = atol (sv->option_b) * 1024;
  601.   while (!(v->Filebuf = AllocMem ((ULONG) v->Filebufmax, MEMF_ANY)))
  602.     {
  603.  
  604.       if (v->Filebufmax > 1024)
  605.     v->Filebufmax -= 1024;
  606.       else
  607.     {
  608.       FreeMem (v, (long) sizeof (struct Vars));
  609.       goto nomem;
  610.     }
  611.     }
  612.  
  613.   /* If framelength was intended to match buffer size, stay in sync */
  614.   v->Tframlen = atol (sv->option_f);
  615.   if (v->Tframlen && v->Tframlen == origbuf)
  616.     v->Tframlen = v->Filebufmax;
  617.  
  618.   v->ErrorLimit = atol (sv->option_e);
  619.  
  620.   /* Copy caller's io struct into our Vars for easier passing */
  621.   v->io = *io;
  622.  
  623. #ifdef DEBUGLOG
  624.   if (!DebugLog)
  625.     DebugLog = (char *) (*v->io.xpr_fopen) (DebugName, "w");
  626.   dlog (v, "XPR_IO struct:\n");
  627.   for (i = 0, lng = (long *) io; i < sizeof (struct XPR_IO) / 4; ++i)
  628.     {
  629.       xprsprintf (v->Msgbuf, "  %08lx\n", *lng++);
  630.       dlog (v, v->Msgbuf);
  631.     }
  632.   D (DEBUGINFO);
  633. #endif
  634.  
  635.   /* Get baud rate; set serial port mode if necessary (and possible) */
  636.   if (v->io.xpr_setserial)
  637.     {
  638.       v->Oldstatus = (*v->io.xpr_setserial) (-1L);
  639.       if (v->Oldstatus != -1)
  640.     {
  641.       /*
  642.          * ZModem requires 8 data bits, no parity (full transparency),
  643.          *  leave other settings alone
  644.        */
  645.       newstatus = v->Oldstatus & 0xFFFFE0BC;
  646.       /*
  647.          * newstatus |= on_flags; Here's where we'd turn bits on if we
  648.          * needed to
  649.        */
  650.       if (newstatus != v->Oldstatus)
  651.         (*v->io.xpr_setserial) (newstatus);
  652.       v->Baud = bauds[(newstatus >> 16) & 0xFF];
  653.  
  654. #ifdef DEBUGLOG
  655.       xprsprintf (v->Msgbuf,
  656.               "Old serial status = %lx, new = %lx, baud = %ld\n",
  657.               v->Oldstatus, newstatus, v->Baud);
  658.       dlog (v, v->Msgbuf);
  659.       D (DEBUGINFO);
  660. #endif
  661.  
  662.     }
  663.       else
  664.     v->Baud = 2400;
  665.       /* If no xpr_setserial(), muddle along with most likely guess */
  666.     }
  667.   else
  668.     v->Baud = 2400;
  669.  
  670.   v->ksize = atol(sv->option_m);
  671.  
  672.   return v;
  673. }                /* End of struct Vars *setup() */
  674.  
  675. /**********************************************************
  676.  *      void set_textmode(struct Vars *v)
  677.  *
  678.  * Set text/binary mode flags in accordance with T option
  679.  * setting
  680.  **********************************************************/
  681. void
  682. set_textmode (struct Vars *v)
  683. {
  684.   struct SetupVars *sv;
  685.   long i;
  686.  
  687. #ifdef DEBUGLOG
  688.   D (DEBUGINFO);
  689. #endif
  690.  
  691.   sv = (void *) v->io.xpr_data;
  692.   switch (*sv->option_t)
  693.     {
  694.     case 'Y':            /* Force text mode on receive; suggest text mode on send */
  695.     TY:
  696.       v->Rxascii = TRUE;
  697.       v->Rxbinary = FALSE;
  698.       v->Lzconv = ZCNL;
  699.       break;
  700.     case 'N':            /* Force binary mode on receive; suggest binary mode on send */
  701.     TN:
  702.       v->Rxascii = FALSE;
  703.       v->Rxbinary = TRUE;
  704.       v->Lzconv = ZCBIN;
  705.       break;
  706.     case 'C':            /* Ask comm program for proper mode for this file */
  707.       if (v->io.xpr_finfo)
  708.     {
  709.       i = (*v->io.xpr_finfo) (v->Filename, 2L);
  710.       if (i == 1)        /* Comm program says use binary mode */
  711.         goto TN;
  712.       if (i == 2)        /* Comm program says use text mode */
  713.         goto TY;
  714.     }
  715.       /* xpr_finfo() not provided (or failed); default to T? */
  716.     case '?':
  717.       v->Rxascii = v->Rxbinary = FALSE;
  718.       v->Lzconv = 0;
  719.       break;
  720.     }
  721. }                /* End of void set_textmode() */
  722.  
  723. /**********************************************************
  724.  *      UBYTE *find_option(UBYTE *buf, UBYTE option)
  725.  *
  726.  * Search for specified option setting in string
  727.  **********************************************************/
  728. UBYTE *
  729. find_option (UBYTE * buf, UBYTE option)
  730. {
  731.   while (*buf)
  732.     {
  733.       buf += strspn (buf, " ,\t\r\n");
  734.       if (*buf == option)
  735.     return ++buf;
  736.       buf += strcspn (buf, " ,\t\r\n");
  737.     }
  738.  
  739.   return NULL;
  740. }                /* End of UBYTE *find_option() */
  741.  
  742. /**********************************************************
  743.  *      void canit(struct Vars *v)
  744.  *
  745.  * send cancel string to get the other end to shut up
  746.  **********************************************************/
  747. void
  748. canit (struct Vars *v)
  749. {
  750.   static char canistr[] =
  751.   {
  752.     24, 24, 24, 24, 24, 24, 24, 24, 24, 24,
  753.     8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 0};
  754.  
  755. #ifdef DEBUGLOG
  756.   D (DEBUGINFO);
  757. #endif
  758.  
  759.   zmputs (v, canistr);
  760. }                /* End of void canit() */
  761.  
  762. /**********************************************************
  763.  *      void zmputs(struct Vars *v, UBYTE *s)
  764.  *
  765.  * Send a string to the modem, with processing for \336 (sleep 1 sec)
  766.  * and \335 (break signal, ignored since XPR spec doesn't support it)
  767.  **********************************************************/
  768. void
  769. zmputs (struct Vars *v, UBYTE * s)
  770. {
  771.   UBYTE c;
  772.  
  773. #ifdef DEBUGLOG
  774.   D (DEBUGINFO);
  775. #endif
  776.  
  777.   while (*s)
  778.     {
  779.       switch (c = *s++)
  780.     {
  781.     case '\336':
  782.       Delay (50L);
  783.     case '\335':
  784.       break;
  785.     default:
  786.       sendline (v, c);
  787.     }
  788.     }
  789.   sendbuf (v);
  790. }                /* End of void zmputs() */
  791.  
  792. /**********************************************************
  793.  *      void xsendline(struct Vars *v, UBYTE c)
  794.  *
  795.  * Write one character to the modem
  796.  **********************************************************/
  797. void
  798. xsendline (struct Vars *v, UBYTE c)
  799. {
  800.   v->Outbuf[v->Outbuflen++] = c;
  801.   if (v->Outbuflen >= sizeof (v->Outbuf))
  802.     sendbuf (v);
  803.  
  804. #ifdef DEBUGLOG
  805.   D (DEBUGINFO);
  806. #endif
  807.  
  808. }                /* End of void xsendline() */
  809.  
  810. /**********************************************************
  811.  *      void sendbuf(struct Vars *v)
  812.  *
  813.  * Send any data waiting in modem output buffer
  814.  **********************************************************/
  815. void
  816. sendbuf (struct Vars *v)
  817. {
  818. #ifdef DEBUGLOG
  819.   D (DEBUGINFO);
  820. #endif
  821.  
  822.   if (v->Outbuflen)
  823.     {
  824.       (*v->io.xpr_swrite) (v->Outbuf, (long) v->Outbuflen);
  825.       v->Outbuflen = 0;
  826.     }
  827. }                /* End of void sendbuf() */
  828.  
  829. /**********************************************************
  830.  *      short readock(struct Vars *v, short tenths)
  831.  *
  832.  * Get a byte from the modem;
  833.  * return TIMEOUT if no read within timeout tenths of a
  834.  * second, return RCDO if carrier lost or other fatal error
  835.  * (sread returns -1).  Added in some buffering so we
  836.  * wouldn't hammer the system with single-byte serial port
  837.  * reads.  Also, the buffering makes char_avail() a lot
  838.  * easier to implement.
  839.  **********************************************************/
  840. short
  841. readock (struct Vars *v, short tenths)
  842. {
  843.   long t;
  844.  
  845. #ifdef DEBUGLOG
  846.   D (DEBUGINFO);
  847. #endif
  848.  
  849.   /* If there's data waiting in our buffer, return next byte */
  850.   if (v->Modemcount)
  851.     {
  852.     gotdata:
  853.       --v->Modemcount;
  854.       return (short) (*v->Modemchar++);
  855.     }
  856.   /*
  857.      * Our buffer is empty; see if there's anything waiting in system buffer.
  858.      * If the caller is in a hurry, don't wait around, but if it can spare
  859.      * a half second, wait a bit and build up some input so we don't do as
  860.      * many sread() calls.
  861.    */
  862.   t = (tenths < 5) ? 0 : 500000;
  863.  
  864. #ifdef DEBUGLOG
  865.   xprsprintf (v->Msgbuf,
  866.           "Input buffer empty; calling sread for %ld bytes, %ld usec\n",
  867.           (long) sizeof (v->Modembuf), t);
  868.   dlog (v, v->Msgbuf);
  869.   D (DEBUGINFO);
  870. #endif
  871.   v->Modemcount = (*v->io.xpr_sread) (v->Modembuf, (long) sizeof (v->Modembuf), t);
  872.  
  873. #ifdef DEBUGLOG
  874.   xprsprintf (v->Msgbuf, "   sread returned %ld\n", v->Modemcount);
  875.   dlog (v, v->Msgbuf);
  876.   D (DEBUGINFO);
  877. #endif
  878.   if (v->Modemcount < 0)    /* Carrier dropped or other fatal error; abort */
  879.     {
  880.       v->Modemcount = 0;
  881.       return RCDO;
  882.     }
  883.   else if (!v->Modemcount)    /* Nothing in system buffer; try waiting */
  884.     {
  885.       t = tenths * 100000L - t;
  886. #ifdef DEBUGLOG
  887.       xprsprintf (v->Msgbuf, "   calling sread for 1 byte, %ld usec\n", t);
  888.       dlog (v, v->Msgbuf);
  889.       D (DEBUGINFO);
  890. #endif
  891.       v->Modemcount = (*v->io.xpr_sread) (v->Modembuf, 1L, t);
  892. #ifdef DEBUGLOG
  893.       xprsprintf (v->Msgbuf, "   sread returned %ld\n", v->Modemcount);
  894.       dlog (v, v->Msgbuf);
  895.       D (DEBUGINFO);
  896. #endif
  897.       if (v->Modemcount < 0)
  898.     {
  899.       v->Modemcount = 0;
  900.       return RCDO;
  901.     }
  902.       else if (!v->Modemcount)    /* Nothing received in time */
  903.     return TIMEOUT;
  904.     }
  905.   v->Modemchar = v->Modembuf;    /* Reset buffer pointer to start of data */
  906.   goto gotdata;
  907. }                /* End of short readock() */
  908.  
  909. /**********************************************************
  910.  *      char char_avail(struct Vars *v)
  911.  *
  912.  * Check if there's anything available to read from the
  913.  * modem
  914.  **********************************************************/
  915. char
  916. char_avail (struct Vars *v)
  917. {
  918. #ifdef DEBUGLOG
  919.   D (DEBUGINFO);
  920. #endif
  921.  
  922.   if (v->Modemcount)
  923.     return TRUE;
  924.  
  925.   /* No data in our buffer; check system's input buffer */
  926.   v->Modemcount = (*v->io.xpr_sread)
  927.     (v->Modembuf, (long) sizeof (v->Modembuf), 0L);
  928.   if (v->Modemcount < 1)    /* Nothing in system buffer either */
  929.     {
  930.       v->Modemcount = 0;
  931.       return FALSE;
  932.     }
  933.   else
  934.     /* System buffer had something waiting for us */
  935.     {
  936.       v->Modemchar = v->Modembuf;
  937.       return TRUE;
  938.     }
  939. }                /* End of char char_avail() */
  940.  
  941. /**********************************************************
  942.  *      void update_rate(struct Vars *v)
  943.  *
  944.  * Update the elapsed time, expected total time, and
  945.  * effective data transfer rate values for status display
  946.  **********************************************************/
  947. void
  948. update_rate (struct Vars *v)
  949. {
  950.   ULONG sent, elapsed, expect;
  951.   short hr, min;
  952.   struct timeval tv;
  953.  
  954. #ifdef DEBUGLOG
  955.   D (DEBUGINFO);
  956. #endif
  957.  
  958.   /* Compute effective data rate so far in characters per second */
  959.   sent = v->xpru.xpru_bytes - v->Strtpos;
  960.   getsystime (&tv);
  961.   elapsed = (tv.tv_secs & 0x7FFFFF) * 128 + tv.tv_micro / 8192;
  962.   elapsed -= (v->Starttime.tv_secs & 0x7FFFFF) * 128
  963.     + v->Starttime.tv_micro / 8192;
  964.   if (elapsed < 128 || elapsed > 0x7FFFFF)
  965.     /*                      ^^^^^^^^^^^^^^^^^^ Kludge for the GURU!  -WMP- */
  966.     elapsed = 128;
  967.   /*
  968.      * If we haven't transferred anything yet (just starting), make reasonable
  969.      * guess (95% throughput); otherwise, compute actual effective transfer
  970.      * rate
  971.    */
  972.   v->xpru.xpru_datarate = (sent) ? (sent * 128 / elapsed)
  973.     : (v->Baud * 95 / 1000);
  974.  
  975.   /* Compute expected total transfer time based on data rate so far */
  976.   if (v->xpru.xpru_filesize < 0)
  977.     expect = 1;        /* Don't know filesize; display time=1; was 0 thas to nice for GURU 8000 0005 */
  978.   else
  979.   {
  980.    /* Save the 8000 0005 GURU!!! */
  981.    if((v->xpru.xpru_datarate != 0) && ((v->xpru.xpru_filesize - v->Strtpos) != 0))
  982.       expect = (v->xpru.xpru_filesize - v->Strtpos) / v->xpru.xpru_datarate;
  983.     else
  984.       expect = 1; /* Display 1 secs better than nothing... */
  985.   }
  986.  
  987.   hr = expect / 3600;        /* How many whole hours */
  988.   expect -= hr * 3600;        /* Remainder not counting hours */
  989.   min = expect / 60;        /* How many whole minutes */
  990.   expect -= min * 60;        /* Remaining seconds */
  991.   xprsprintf (v->Msgbuf, "%02ld:%02ld:%02ld", (long) hr, (long) min, expect);
  992.   v->xpru.xpru_expecttime = (char *) v->Msgbuf;
  993.  
  994.   /* Compute elapsed time for this transfer so far */
  995.   elapsed /= 128;
  996.   hr = elapsed / 3600;
  997.   elapsed -= hr * 3600;
  998.   min = elapsed / 60;
  999.   elapsed -= min * 60;
  1000.   xprsprintf (v->Msgbuf + 20, "%02ld:%02ld:%02ld", (long) hr, (long) min,
  1001.           elapsed);
  1002.   v->xpru.xpru_elapsedtime = (char *) v->Msgbuf + 20;
  1003. }                /* End of void update_rate() */
  1004.  
  1005. /**********************************************************
  1006.  *      long bfopen(struct Vars *v, UBYTE *mode)
  1007.  *
  1008.  * Buffered file I/O fopen() interface routine
  1009.  **********************************************************/
  1010. long
  1011. bfopen (struct Vars *v, UBYTE * mode)
  1012. {
  1013.   /* Initialize file-handling variables */
  1014.   v->Filebufpos = v->Filebuflen = v->Filebufcnt = 0;
  1015.   v->Fileflush = FALSE;
  1016.   v->Filebufptr = v->Filebuf;
  1017.   /* Open the file */
  1018. #ifdef DEBUGLOG
  1019.   xprsprintf (v->Msgbuf, "bfopen: %s %s\n", v->Filename, mode);
  1020.   dlog (v, v->Msgbuf);
  1021.   D (DEBUGINFO);
  1022. #endif
  1023.   return (*v->io.xpr_fopen) (v->Filename, mode);
  1024. }                /* End of long bfopen() */
  1025.  
  1026. /**********************************************************
  1027.  *      void bfclose(struct Vars *v)
  1028.  *
  1029.  * Buffered file I/O fclose() interface routine
  1030.  **********************************************************/
  1031. void
  1032. bfclose (struct Vars *v)
  1033. {
  1034. #ifdef DEBUGLOG
  1035.   D (DEBUGINFO);
  1036. #endif
  1037.  
  1038.   if (v->File)
  1039.     {
  1040.       /* If bfwrite() left data in buffer, flush it out before closing */
  1041.       if (v->Fileflush)
  1042.     (*v->io.xpr_fwrite) (v->Filebuf, 1L, v->Filebufcnt, v->File);
  1043.       /* Close the file */
  1044.       (*v->io.xpr_fclose) (v->File);
  1045.       v->File = NULL;
  1046.     }
  1047. }                /* End of void bfclose() */
  1048.  
  1049. /**********************************************************
  1050.  *      void bfseek(struct Vars *v, long pos)
  1051.  *
  1052.  * Buffered file I/O fseek() interface routine
  1053.  **********************************************************/
  1054. void
  1055. bfseek (struct Vars *v, long pos)
  1056. {
  1057.   long offset;
  1058.  
  1059. #ifdef DEBUGLOG
  1060.   D (DEBUGINFO);
  1061. #endif
  1062.  
  1063.   /* If new file position is within currently buffered section,
  1064.      reset pointers */
  1065.   if (pos >= v->Filebufpos && pos < v->Filebufpos + v->Filebuflen)
  1066.     {
  1067.       offset = pos - v->Filebufpos;
  1068.       v->Filebufptr = v->Filebuf + offset;
  1069.       v->Filebufcnt = v->Filebuflen - offset;
  1070.       /* Otherwise, fseek() file & discard buffer contents to force new read */
  1071.     }
  1072.   else
  1073.     {
  1074.       (*v->io.xpr_fseek) (v->File, pos, 0L);
  1075.       v->Filebuflen = v->Filebufcnt = 0;
  1076.       v->Filebufpos = pos;
  1077.     }
  1078. }                /* End of void bfseek() */
  1079.  
  1080. /**********************************************************
  1081.  *      long bfread(struct Vars *v, UBYTE *buf, long length)
  1082.  *
  1083.  * Buffered file I/O fread() interface routine
  1084.  **********************************************************/
  1085. long
  1086. bfread (struct Vars *v, UBYTE * buf, long length)
  1087. {
  1088.   long count, total = 0;
  1089.  
  1090. #ifdef DEBUGLOG
  1091.   D (DEBUGINFO);
  1092. #endif
  1093.  
  1094.   /* Keep going until entire request completed */
  1095.   while (length > 0)
  1096.     {
  1097.       /* Copy as much of the request as possible from the buffer */
  1098.       count = (length <= v->Filebufcnt) ? length : v->Filebufcnt;
  1099.       CopyMem (v->Filebufptr, buf, count);
  1100. #ifdef DEBUGLOG
  1101.       xprsprintf (v->Msgbuf, "bfread got %ld bytes from buffer\n", count);
  1102.       dlog (v, v->Msgbuf);
  1103.       D (DEBUGINFO);
  1104. #endif
  1105.       buf += count;
  1106.       total += count;
  1107.       length -= count;
  1108.       v->Filebufptr += count;
  1109.       v->Filebufcnt -= count;
  1110.  
  1111.       /* If we've emptied the buffer, read next buffer's worth */
  1112.       if (!v->Filebufcnt)
  1113.     {
  1114.       v->Filebufpos += v->Filebuflen;
  1115.       v->Filebufptr = v->Filebuf;
  1116.       v->Filebufcnt = v->Filebuflen
  1117.         = (*v->io.xpr_fread) (v->Filebuf, 1L, v->Filebufmax, v->File);
  1118. #ifdef DEBUGLOG
  1119.       xprsprintf (v->Msgbuf, "bfread read %ld bytes\n", v->Filebufcnt);
  1120.       dlog (v, v->Msgbuf);
  1121.       D (DEBUGINFO);
  1122. #endif
  1123.       /* If we hit the EOF, return with however much we read so far */
  1124.       if (!v->Filebufcnt)
  1125.         break;
  1126.     }
  1127.     }
  1128.   return total;
  1129. }                /* End of long bfread() */
  1130.  
  1131. /**********************************************************
  1132.  *      long bfwrite(struct Vars *v, UBYTE *buf, long length)
  1133.  *
  1134.  * Buffered file I/O fwrite() interface routine
  1135.  **********************************************************/
  1136. long
  1137. bfwrite (struct Vars *v, UBYTE * buf, long length)
  1138. {
  1139.   long count, total = 0;
  1140.  
  1141. #ifdef DEBUGLOG
  1142.   D (DEBUGINFO);
  1143. #endif
  1144.  
  1145.   /* Keep going until entire request completed */
  1146.   while (length > 0)
  1147.     {
  1148.       /* Copy as much as will fit into the buffer */
  1149.       count = v->Filebufmax - v->Filebufcnt;
  1150.       if (length < count)
  1151.     count = length;
  1152.       CopyMem (buf, v->Filebufptr, count);
  1153. #ifdef DEBUGLOG
  1154.       xprsprintf (v->Msgbuf, "bfwrite buffered %ld bytes\n", count);
  1155.       dlog (v, v->Msgbuf);
  1156.       D (DEBUGINFO);
  1157. #endif
  1158.       buf += count;
  1159.       total += count;
  1160.       length -= count;
  1161.       v->Filebufptr += count;
  1162.       v->Filebufcnt += count;
  1163.       v->Fileflush = TRUE;
  1164.  
  1165.       /* If we've filled the buffer, write it out */
  1166.       if (v->Filebufcnt == v->Filebufmax)
  1167.     {
  1168.       count = (*v->io.xpr_fwrite) (v->Filebuf, 1L, v->Filebufcnt, v->File);
  1169. #ifdef DEBUGLOG
  1170.       xprsprintf (v->Msgbuf, "bfwrite wrote %ld bytes\n", count);
  1171.       dlog (v, v->Msgbuf);
  1172.       D (DEBUGINFO);
  1173. #endif
  1174.       if (count < v->Filebufcnt)
  1175.         return -1;
  1176.       v->Filebufptr = v->Filebuf;
  1177.       v->Filebufcnt = 0;
  1178.       v->Fileflush = FALSE;
  1179.     }
  1180.     }
  1181.   return total;
  1182. }                /* End of long bfwrite() */
  1183.  
  1184. /**********************************************************
  1185.  *      void ioerr(struct XPR_IO *io, char *msg)
  1186.  *
  1187.  * Have the comm program display an error message for us,
  1188.  * using a temporary XPR_UPDATE structure; used to display
  1189.  * errors before Vars gets allocated
  1190.  **********************************************************/
  1191. void
  1192. ioerr (struct XPR_IO *io, char *msg)
  1193. {
  1194.   struct XPR_UPDATE xpru;
  1195.  
  1196.   if (io->xpr_update)
  1197.     {
  1198.       xpru.xpru_updatemask = XPRU_ERRORMSG;
  1199.       xpru.xpru_errormsg = msg;
  1200.       (*io->xpr_update) (&xpru);
  1201.     }
  1202. }                /* End of void ioerr() */
  1203.  
  1204. /**********************************************************
  1205.  *      void upderr(struct Vars *v, char *msg)
  1206.  *
  1207.  * Have the comm program display an error message for us, using the
  1208.  * normal XPR_IO structure allocated in Vars
  1209.  **********************************************************/
  1210. void
  1211. upderr (struct Vars *v, char *msg)
  1212. {
  1213.   v->xpru.xpru_updatemask = XPRU_ERRORMSG;
  1214.   v->xpru.xpru_errormsg = msg;
  1215.   if (msg == v->Msgbuf)        /* Ensure message length < 50 */
  1216.     msg[48] = '\0';
  1217.   (*v->io.xpr_update) (&v->xpru);
  1218. #ifdef DEBUGLOG
  1219.   dlog (v, msg);
  1220.   dlog (v, "\n");
  1221.   D (DEBUGINFO);
  1222. #endif
  1223. }                /* End of void upderr() */
  1224.  
  1225. /**********************************************************
  1226.  *      void updmsg(struct Vars *v,char *msg)
  1227.  *
  1228.  * Have the comm program display a normal message for us
  1229.  **********************************************************/
  1230. void
  1231. updmsg (struct Vars *v, char *msg)
  1232. {
  1233. #ifdef DEBUGLOG
  1234.   D (DEBUGINFO);
  1235. #endif
  1236.  
  1237.   v->xpru.xpru_updatemask = XPRU_MSG;
  1238.   v->xpru.xpru_msg = msg;
  1239.   if (msg == v->Msgbuf)        /* Ensure message length < 50 */
  1240.     msg[48] = '\0';
  1241.   (*v->io.xpr_update) (&v->xpru);
  1242. #ifdef DEBUGLOG
  1243.   dlog (v, msg);
  1244.   dlog (v, "\n");
  1245.   D (DEBUGINFO);
  1246. #endif
  1247. }                /* End of void updmsg() */
  1248.  
  1249. /**********************************************************
  1250.  *      long getfree(void)
  1251.  *
  1252.  * Figure out how many bytes are free on the drive we're uploading to.
  1253.  * Stubbed out for now; not supported by XPR spec.
  1254.  **********************************************************/
  1255. long
  1256. getfree (void)
  1257. {
  1258.   return 0x7FFFFFFF;
  1259. }                /* End of long getfree() */
  1260.  
  1261. /**********************************************************
  1262.  *      char exist(struct Vars *v)
  1263.  *
  1264.  * Check whether file already exists; used to detect
  1265.  * potential overwrites
  1266.  **********************************************************/
  1267. char
  1268. exist (struct Vars *v)
  1269. {
  1270.   long file;
  1271.  
  1272. #ifdef DEBUGLOG
  1273.   D (DEBUGINFO);
  1274. #endif
  1275.  
  1276.   file = (*v->io.xpr_fopen) (v->Filename, "r");
  1277.   if (file)
  1278.     {
  1279.       (*v->io.xpr_fclose) (file);
  1280.       return TRUE;
  1281.     }
  1282.   else
  1283.     return FALSE;
  1284. }                /* End of char exist() */
  1285.  
  1286. #ifdef DEBUGLOG
  1287. /**********************************************************
  1288.  *      void dlog(struct Vars *v, UBYTE *s)
  1289.  *
  1290.  * Write a message to the debug log
  1291.  **********************************************************/
  1292. void
  1293. dlog (struct Vars *v, UBYTE * s)
  1294. {
  1295.   /* Open the debug log if it isn't already open */
  1296.   if (!DebugLog)
  1297.     DebugLog = (char *) (*v->io.xpr_fopen) (DebugName, "a");
  1298.   (*v->io.xpr_fwrite) (s, 1L, (long) strlen (s), (long) DebugLog);
  1299.   /*
  1300.      * Close file to flush output buffer; comment these two lines out if
  1301.      * you aren't crashing your system and don't mind waiting until the
  1302.      * transfer finishes to look at your log file.
  1303.    */
  1304.   /* (*v->io.xpr_fclose)((long)DebugLog);
  1305.      * DebugLog = NULL;
  1306.    */
  1307.  
  1308. }                /* End of void dlog() */
  1309. #endif
  1310. /* End of Utils.c source */
  1311.